1 //+-----------------------------------------------------------------------
3 // Copyright (c) Microsoft Corporation. All rights reserved.
9 // 2007/07/20 [....] Created
10 // 2007/09/20 [....] Ported Windows->DevDiv. See SourcesHistory.txt.
12 //------------------------------------------------------------------------
14 #include "precompiled.hxx"
15 #include "WatsonReporting.hxx"
18 #ifdef APPLICATION_SHIM
20 // Curiously, XPSViewer seems capable of coping with all the problems detected here. That's because
21 // it doesn't use ClickOnce and also because if IPersistMoniker marshaling fails, IE's fallback to
22 // IPersistFile still works for XPSViewer.
23 // That's why all this code is conditionally compiled only for PH.exe.
25 // HKCU\Software\Classes is persisted in a separate file and on many computers permissons are set
26 // explicitly, not inherited. This must be somehow part of the explanation of how the ACL entry for the
27 // individual user account can be missing.
28 HRESULT
CheckRegistryAccess()
31 int error
= RegOpenKeyEx(HKEY_CURRENT_USER
, L
"Software\\Classes", 0, KEY_READ
, &hKey
);
32 if (error
== ERROR_SUCCESS
)
38 // Dev10 bug 707086 - HKCU\SOFTWARE\Classes may not exist on clean XP installations.
39 // ClickOnce will create it, so don't bother about it here.
40 if (error
== ERROR_FILE_NOT_FOUND
)
45 HRESULT hr
= HRESULT_FROM_WIN32(error
);
46 TriggerWatson(ActivationProblemIds::HKCUClassesAccessDenied
);
50 // Only read access to %LocalAppData% is tested here. ClickOnce needs access to %LocalAppData%\Deployment.
51 // Other profile folders may also be susceptible to the ACL anomaly, but unless we get actual reports of
52 // such cases, it doesn't make much sense to generalize the test.
53 // Worth noting is that denied access to the Temporary Internet Files folder does not break PresentationHost
55 HRESULT
CheckAppDataFolderAccess()
57 wchar_t path
[MAX_PATH
];
58 HRESULT hr
= SHGetFolderPath(0, CSIDL_LOCAL_APPDATA
, 0, SHGFP_TYPE_CURRENT
, path
);
61 StringCchCat(path
, ARRAYSIZE(path
), L
"\\*");
62 WIN32_FIND_DATA findData
;
63 HANDLE hFind
= FindFirstFile(path
, &findData
);
64 if(hFind
!= INVALID_HANDLE_VALUE
)
68 else if(GetLastError() == ERROR_ACCESS_DENIED
)
70 TriggerWatson(ActivationProblemIds::AppDataFolderAccessDenied
);
77 void TriggerWatson(LPCWSTR problemId
)
81 // Invoke Watson in manifest mode:
82 // http://msdn2.microsoft.com/en-us/library/bb219076.aspx#MicrosoftErrorReporting_AboutManifestMode
83 // We rely on the .NET Framework setup to install dw20.exe.
87 const wchar_t report
[] = CRLF
// required blank line
88 L
"Version=131072" CRLF
89 L
"ReportingFlags=2048" CRLF
// fDwrCriticalEvent
90 L
"General_AppName=" TEXT(SHIM_COMPONENT_DESCRIPTION
) CRLF
91 L
"FilesToKeep=null" CRLF
92 L
"EventType=" ACTIVATION_PROBLEM_WATSON_EVENT CRLF
//***
93 L
"P1=" TEXT(TARGETNAME
) CRLF
94 L
"P2=" TEXT(FX_VER_FILEVERSION_STR
) CRLF
;
95 //P3=OS version - added below
96 //P4=problemId - added below
98 OSVERSIONINFOEX OSInfo
= { sizeof OSInfo
};
101 wchar_t DWPath
[MAX_PATH
];
103 wchar_t cmdLine
[3*MAX_PATH
];
104 STARTUPINFO startupInfo
= { sizeof STARTUPINFO
};
105 PROCESS_INFORMATION processInfo
;
108 // Create the report file
109 wchar_t reportFilepath
[MAX_PATH
] = { 0 };
110 GetTempPath(ARRAYSIZE(reportFilepath
), reportFilepath
);
111 CHECK_ZERO_FROM_WIN32(GetTempFileName(reportFilepath
, L
"PH", 0, reportFilepath
));
112 hFile
= CreateFile(reportFilepath
, GENERIC_WRITE
, 0, 0, CREATE_ALWAYS
, 0, 0);
113 CHECK_BOOL_FROM_WIN32(hFile
&& hFile
!= INVALID_HANDLE_VALUE
);
114 CHECK_BOOL_FROM_WIN32(WriteFile(hFile
, report
, sizeof report
- sizeof L
'\0', &cBytesWritten
, 0));
115 if(GetVersionEx(reinterpret_cast<OSVERSIONINFO
*>(&OSInfo
)))
117 wchar_t strOSVersion
[96];
119 GetNativeSystemInfo(&sysInfo
);
120 StringCchPrintf(strOSVersion
, ARRAYSIZE(strOSVersion
),
121 L
"P3=%d.%d.%d.%d.%d%s" CRLF
,
122 OSInfo
.dwMajorVersion
, OSInfo
.dwMinorVersion
, OSInfo
.dwBuildNumber
,
123 OSInfo
.wServicePackMajor
, OSInfo
.wServicePackMinor
,
124 sysInfo
.wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_AMD64
? L
" (x64)" : L
"");
125 WriteFile(hFile
, strOSVersion
, (DWORD
)wcslen(strOSVersion
)*2, &cBytesWritten
, 0);
129 WriteFile(hFile
, L
"P4=", 3*sizeof(wchar_t), &cBytesWritten
, 0);
130 WriteFile(hFile
, problemId
, (DWORD
)wcslen(problemId
)*sizeof(*problemId
), &cBytesWritten
, 0);
131 WriteFile(hFile
, CRLF
, sizeof CRLF
- sizeof L
'\0', &cBytesWritten
, 0);
135 // Invoke dw20.exe -d <report filepath>
136 // Using ShellExecute() would be simpler, but it relies heavily on registry keys, and we have an ACL
137 // problem, so ShellExecute() might fail.
139 // Apparently DW is installed only as a 32-bit build.
141 cch
= GetEnvironmentVariable(L
"CommonProgramFiles(x86)", DWPath
, ARRAYSIZE(DWPath
));
143 cch
= GetEnvironmentVariable(L
"CommonProgramFiles", DWPath
, ARRAYSIZE(DWPath
));
145 CKHR(StringCchCopy(DWPath
+cch
, ARRAYSIZE(DWPath
)-cch
, L
"\\Microsoft Shared\\DW\\dw20.exe"));
146 // Conventionally, the first command line item is the executable's filepath.
147 CKHR(StringCchPrintf(cmdLine
, ARRAYSIZE(cmdLine
), L
"\"%s\" -d \"%s\"", DWPath
, reportFilepath
));
148 CHECK_BOOL_FROM_WIN32(CreateProcess(DWPath
, cmdLine
, 0, 0, 0, 0, 0, 0, &startupInfo
, &processInfo
));
149 WaitForSingleObject(processInfo
.hProcess
, INFINITE
);
150 CHECK_BOOL_FROM_WIN32(GetExitCodeProcess(processInfo
.hProcess
, &exitCode
));
151 hr
= exitCode
== 0 ? S_OK
: E_FAIL
;
154 // No cleanup really needed. Mission failed...
156 // Fallback: just raise an exception
159 ReportFaultAndTerminate(hr
, ACTIVATION_PROBLEM_FALLBACK_EXCEPTION_CODE
);
163 #endif // APPLICATION_SHIM